package org.gulugulubiao.utils;

import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

@Component
public class RedisIdUtil {
    private static final long BEGIN_TIMESTAMP = 1640995200L;// 开始时间戳
    private static final int COUNT_BITS = 32; //32个bits

    public static long nextId(String keyPrefix, StringRedisTemplate stringRedisTemplate) {
        if (stringRedisTemplate == null) {
            throw new RuntimeException("自动装配失败！");
        }
        // 唯一Id格式： 64位：最高位0 后面31位为时间戳  再后面32位为序列号
        // 为什么是64位呢？因为long类型数就是64位，这个id用long装
        // 1.生成时间戳
        LocalDateTime curDateTime = LocalDateTime.now();
        long curSeconds = curDateTime.toEpochSecond(ZoneOffset.UTC);
        long timestamp = curSeconds - BEGIN_TIMESTAMP;

        // 2.生成序列号
        // 2.1.获取当前日期，精确到天
        String date = curDateTime.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        // 2.2.自增长
        long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);

        // 3.时间戳左移32位
        long l = timestamp << COUNT_BITS;
        // 如果距离 BEGIN_TIMESTAMP 太久远，时间戳由 long 转 bit 后位数过长（大于31位），此时再往左移，高位就会被截断，那么就会与生成过的时间戳重复

        // 4.时间戳与序列号拼接并返回
        return l | count; //按位或
    }

}
